package org.seven.jrdp.commons.shiro.filter;

import java.io.Serializable;
import java.util.LinkedList;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.cache.Cache;
import org.seven.jrdp.commons.util.ServletUtils;

public class TimeoutFilter extends AccessControlFilter {
	private static final String SESSION_KEY = TimeoutFilter.class.getSimpleName();
	private static final String CACHE_KEY = "timeout_";

	private Cache cache;
	private SessionDAO sessionDAO;
	private int maxSession;

	public void setCache(Cache cache) {
		this.cache = cache;
	}

	public void setSessionDAO(SessionDAO sessionDAO) {
		this.sessionDAO = sessionDAO;
	}

	public void setMaxSession(int maxSession) {
		this.maxSession = maxSession;
	}

	@Override
	public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
		return false;
	}

	@Override
	@SuppressWarnings("unchecked")
	protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
		Subject subject = getSubject(request, response);
		if (!subject.isAuthenticated() && !subject.isRemembered()) {
			if (ServletUtils.isAjax(WebUtils.toHttp(request))) {
				ServletUtils.writeTimeout(WebUtils.toHttp(response), WebUtils.toHttp(request).getContextPath() + getLoginUrl());
				return false;
			} else {
				return true;
			}
		}
		Session session = subject.getSession();
		String account = (String) subject.getPrincipal();
		Serializable sessionId = session.getId();
		LinkedList<Serializable> list = cache.get(CACHE_KEY + account, LinkedList.class);
		if (list == null) {
			list = new LinkedList<Serializable>();
		}
		if (!list.contains(sessionId) && session.getAttribute(SESSION_KEY) == null) {
			list.push(sessionId);
		}
		while (list.size() > maxSession) {
			Serializable kickoutSessionId = null;
			kickoutSessionId = list.removeLast();
			try {
				Session kickoutSession = sessionDAO.readSession(kickoutSessionId);
				if (kickoutSession != null) {
					kickoutSession.setAttribute(SESSION_KEY, true);
					sessionDAO.update(kickoutSession);
				}
			} catch (Exception e) {
			}
		}
		cache.put(CACHE_KEY + account, list);
		if (session.getAttribute(SESSION_KEY) != null) {
			try {
				subject.logout();
			} catch (Exception e) {
			}
			if (ServletUtils.isAjax(WebUtils.toHttp(request))) {
				ServletUtils.writeTimeout(WebUtils.toHttp(response), WebUtils.toHttp(request).getContextPath() + getLoginUrl());
			} else {
				WebUtils.issueRedirect(request, response, getLoginUrl());
			}
			return false;
		}
		return true;
	}
}